<script lang="ts" setup>
/**
 * Expose
 * @change 手动切换当前act key值
 *
 * v-model:value 当前活跃的值，动态绑定
 *
 * Props
 * @config tabs配置项 --IConfig [{ key: string, label: string, dot?: number | string | boolean, num?: number | string }, ...]
 * 必传
 *
 * @key 当前active
 * 默认config第一项key值
 *
 * @line 是否显示滑动下划线
 * 默认 false
 *
 * @hiddenDistance 两端淡入淡出效果距离
 * 默认140rpx
 *
 * Emits
 * @tag 返回当前key值
 */
import { computed, getCurrentInstance, nextTick, ref, watch } from 'vue'
import type { ComponentInternalInstance } from 'vue'
import { debounce, hasUnit } from '@U/common'
import type { IObj, PropType } from '@/interface'
import { hasVarNumber, hasVarString } from '@/interface'

interface IConfig {
  label: string,
  key: any,
  dot?: number | string | boolean, // true时红点 | string时为红点内容
  num?: string | number, // tag 右侧定位数量
}
const { proxy: _this } = getCurrentInstance() as ComponentInternalInstance
const props = defineProps({
  config: {
    type: Object as PropType<Array<IConfig>>,
    required: true,
  },
  key: {
    type: String,
    required: false,
    default: '',
  },
  line: {
    type: Boolean,
    required: false,
    default: false,
  },
  hiddenDistance: {
    type: String,
    required: false,
    default: '60',
  },
  value: {
    type: String,
    required: false,
    default: '',
  },
  tagNameStyles: {
    type: Object,
    required: false,
    default: () => ({}),
  },
})
const emits = defineEmits(['tag', 'update:value'])

// 当前act
const act = ref(props?.value || props?.key || props.config[0].key)
// 改变act
const change = (key: string) => { act.value = key }
watch(
    () => act.value,
    (newVal: string) => {
      emits('tag', newVal, props.config.filter((i: IObj) => i.key === act.value)[0])
      emits('update:value', newVal)
    },
)
watch(
    () => props.value,
    (newVal: string) => {
      act.value = newVal
    },
)
// 当前组件宽度
const tagsWidth = ref(<number>0)
const tagWidth = ref(<Array<number>>[])
const lineWidth = ref(<number>0)
const hiddenWidth = ref(<number>0)
const elQuery = uni.createSelectorQuery().in(_this)

// 监听config 实时变化宽度
const _config = computed(() => JSON.stringify(props.config))
function getEL() {
  nextTick(() => {
    elQuery.select('.prm-tag-state')
        .boundingClientRect((d: IObj) => {
          tagsWidth.value = d?.width
        })
        .exec()
    if (props?.line) {
      elQuery.selectAll('.prm-tag')
          .boundingClientRect((d: IObj) => {
            tagWidth.value = (d as Array<IObj>).map((i: IObj) => (i?.width))
          })
          .exec()
      elQuery
          .select('.prm-tag-line')
          .boundingClientRect((d: IObj) => {
            lineWidth.value = d?.width
          })
          .exec()
      elQuery
          .select('.prm-tag-hidden-l')
          .boundingClientRect((d: IObj) => {
            hiddenWidth.value = d?.width
          })
          .exec()
    }
  })
}
getEL()
const autoGetEl = debounce(() => getEL())
watch(
    () => _config.value,
    () => {
      autoGetEl()
    },
)

// 当前act位置数量
const actNumber = computed(() => props.config.map((d: IConfig) => d.key).indexOf(act.value))
// line平移距离
const actLineDistance = computed(() => {
  if (props?.line) {
    // 平移每一份的距离
    const oneElWidth = tagWidth.value[actNumber.value]
    // 平移一份居中的距离
    const oneDistance = (oneElWidth - lineWidth.value) / 2 - (actNumber.value !== tagWidth.value.length - 1 ? 12 : 0)
    // 如果内容不能撑满容器时，每次移动添加的间距
    let paddingWidth = 0
    let allStateWidth = 0
    tagWidth.value.forEach(i => {
      allStateWidth += i
    })
    const paddingAllWidth = (tagsWidth.value - 2 * hiddenWidth.value) - allStateWidth
    if (paddingAllWidth > 0) {
      paddingWidth = paddingAllWidth / (tagWidth.value.length - 1)
    }
    // 已平移的距离
    let beforeDistance = 0
    tagWidth.value.forEach((d, i) => {
      if (i < actNumber.value) {
        beforeDistance += d
      }
    })
    return hiddenWidth.value + oneDistance + beforeDistance + paddingWidth * actNumber.value
  }
  return hiddenWidth.value
})

</script>

<template>
  <div class="prm-tag-state">
    <div :style="{width: hasUnit(hiddenDistance)}" class="prm-tag-hidden-l" />
    <div :style="{width: hasUnit(hiddenDistance)}" class="prm-tag-hidden-r" />
    <div :style="{padding: `0rpx ${hasUnit(hiddenDistance)}`}" class="prm-tag-box">
      <div v-if="line" :style="{left: `${actLineDistance}px`}" class="prm-tag-line" />
      <div
        v-for="(d, index) in config"
        :key="d.key"
        :class="(act === d.key ? 'act' : '')"
        :style="{...tagNameStyles}"
        class="prm-tag"
        @tap="change(d.key)"
      >
        <!-- d.label.length*30+8 => d.label.length是tab文字长度 30是文字大小 8是根据有右边距的tab算出来的-->
        <div v-if="d.dot" :style="index === config.length-1 ? `left: ${d.label.length*30+8}rpx` : 'right: 20rpx'" class="prm-tag-dot">{{ (hasVarString(d.dot) || hasVarNumber(d.dot)) ? d.dot : '' }}</div>
        {{ d.label }}{{ d.num && (hasVarString(d.num) || hasVarNumber(d.num)) ? ` (${d.num})` : '' }}
      </div>
    </div>
  </div>
</template>

<style lang="less" scoped>
.prm-tag-state {
  background: white;
  width: 100%;
  height: 90rpx;
  position: relative;
  .prm-tag-hidden-l, .prm-tag-hidden-r {
    position: absolute;
    top: 0;
    height: 100%;
    z-index: 10;
  }
  .prm-tag-hidden-l {
    left: 0;
    background: linear-gradient(to right, #ffffff, rgba(255, 255, 255, 0.15));
  }
  .prm-tag-hidden-r {
    right: 0;
    background: linear-gradient(to left, #ffffff, rgba(255, 255, 255, 0.15));
  }
  .prm-tag-box {
    height: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    display: flex;
    align-items: center;
    justify-content: space-between;
    position: relative;
    .prm-tag-line {
      width: 46rpx;
      height: 4rpx;
      border-radius: 4rpx;
      background: #1890FF;
      transition: all .3s;
      position: absolute;
      bottom: 0;
    }
    .prm-tag {
      white-space: nowrap;
      height: 100%;
      padding-right:24px;
      display: flex;
      align-items: center;
      font-size: 30rpx;
      transition: all .3s;
      color:#00000073;
      position: relative;
      .prm-tag-dot {
        z-index: 10;
        position: absolute;
        //right: 20rpx;
        top: 18rpx;
        width: 18rpx;
        height: 18rpx;
        border-radius: 50%;
        background: #ff4d4f;
        color: white;
        font-size: 12rpx;
        display: flex;
        justify-content: center;
        align-items: center;
        overflow: hidden;
      }
    }
    :last-child {
      padding-right: 0;
    }
    .act {
      font-weight: 600;
      color: #1890FF;
    }
  }
}
</style>
